创建表
# app文件夹下的 models.py
class Student(models.Model):
id = models.AutoField(max_length=11, primary_key=True)
name = models.CharField(max_length=11)
# SQL 语句
create table student(
id int(11) auto_increment primary key,
name varchar(11)
) engine=innodb default charset=utf8;
通过 ORM 创建/修改/删除表,都要执行两条命令
1. 通过 ORM 创建/修改/删除表,都要执行两条命令
- 在cmd中执行
python manage.py makemigrations # 记录 models.py 中所改动的内容
# 所改动的记录都会保存在 app 文件夹下的 migrations 文件夹里
# 如果不是通过 ORM 去修改数据库的表,而是直接通过数据库可视化工具去修改,肯定会报错,这时把 migrations 文件夹里的文件删掉(__init__.py 除外) 和 数据库中的所有表,重新执行这两条命令就可以了
python manage.py migrate # 将 models.py 中的内容转换成SQL语句然后执行
- 使用 Pycharm 中的 Run manage.py Task (在 Tools 里,快捷键: Ctrl+Alt+R),直接输入下面两个单词就可以了
makemigrations
migrate
- 注意:
- 当执行 python manage.py makemigrations 或 makemigrations 时,无法识别 app 中的 model ,只识别到 django 自带的 auth、admin、token 等表的时候,此时在 app 目录下创建一个 migrations 文件夹,然后里面放一个空的 __init__.py 文件即可
设置提示功能
1. 设置提示功能
- 如果没有设置提示功能的前提下直接打印查询到的数据的时候,会直接显示一个内存地址或者是一个对象
# models.py
class Student(models.Model):
username = models.CharField(max_length=10)
age = models.IntegerField()
# views.py
def view_fn(request):
student_data = Student.objects.all()
student = Student.objects.get(id=1)
print(student_data) # <QuerySet [<Student: Student object>, <Student: Student object>, <Student: Student object>, <Student: Student object>]>
print(student) # Student object
return render(request, 'index.html')
- 使用类中的双下划线方法 __str__ 实现提示功能(不懂的可以看回面向对象中的 __str__ 方法)
# models.py
class Student(models.Model):
username = models.CharField(max_length=10)
age = models.IntegerField()
# 设置提示功能 -> python3 会执行 __str__
def __str__(self):
return 'username:{}, age:{}'.format(self.username, self.age)
# 设置提示功能 -> python3 会执行 __unicode__
def __unicode__(self):
return 'username:{}, age:{}'.format(self.username, self.age)
# views.py
def view_fn(request):
student_data = Student.objects.all()
student = Student.objects.get(id=1)
print(student_data) # <QuerySet [<Student: username:Yeung, age:23>, <Student: username:Kevin, age:18>, <Student: username:Eric, age:22>, <Student: username:Eric, age:22>]>
print(student) # username:Yeung, age:23
return render(request, 'test.html')
字段
1. 常用的字段类
- AutoField()
- 自增整形字段
- 必传参数: primary_key=True -> 设置为主键
- 没有 AutoField() 字段时 Django 会自动帮你创建
- 一个类中不能有两个 AutoField()
class TestTable(models.Model):
id = models.AutoField(primary_key=True)
- IntegerField()
- int 类型
- 数值范围: -2147483648 ~ 2147483647
class TestTable(models.Model):
age = models.IntegerField(max_length=11)
- CharField()
- varchar 类型
- 必传参数: max_length=num
- max_length 表示字符长度
class TestTable(models.Model):
name = models.CharField(max_length=15)
- DateField()
- date 类型
- 日期格式: YYYY-MM-DD(1000-01-01 ~ 9999-12-31)
- 参数:
- auto_now = True/False -> 无论是添加数据还是修改数据,都会添加当前时间
- auto_now_add = True/False -> 只有在添加数据的时候才会添加当前时间,修改不会
- auto_now 和 auto_now_add 不能同时进行设置,下面只是为了演示
class TestTable(models.Model):
this_date = models.DateField(auto_now=False, auto_now_add=True)
- DatetimeField()
- datetime 类型
- 日期格式: YYYY-MM-DD HH:MM:SS(1000-01-01 00:00:00 ~ 9999-12-31 23:59:59)
- 参数:
- auto_now = True/False -> 无论是添加数据还是修改数据,都会添加当前时间
- auto_now_add = True/False -> 只有在添加数据的时候才会添加当前时间,修改不会
- auto_now 和 auto_now_add 不能同时进行设置,下面只是为了演示
class TestTable(models.Model):
this_date = models.DateTimeField(auto_now=False, auto_now_add=True)
- TimeField()
- time 类型
- 日期格式: HH:MM:SS('-838:59:59' ~ '838:59:59')
- 参数:
- auto_now = True/False -> 无论是添加数据还是修改数据,都会添加当前时间
- auto_now_add = True/False -> 只有在添加数据的时候才会添加当前时间,修改不会
- auto_now 和 auto_now_add 不能同时进行设置,下面只是为了演示
class TestTable(models.Model):
this_date = models.TimeField(auto_now=False, auto_now_add=True)
- DateField() 和 DatetimeField() 和TimeField() 的注意事项:
- DateField() 和 DatetimeField() 和TimeField()所传的参数都是一样的
- auto_now、auto_now_add 与 default 是互斥的,也就是说,当你把它三或者其中的两个放在一起就会报错,上面只是为了演示才写在一起
- 当你将 auto_add_now 或者 auto_now 设置为 True 会引起 editable=False 和 blank=True(editable若为False,在admin界面或其他的表单(ModelForm)中则不会显示这一列的情况)
2. 字段类合集
- 字段类型,详情可点击查询官网
分类 | ORM字段类 | 说明 |
自增 | AutoField() |
|
BigAutoField() |
| |
布尔 | BooleanField() |
|
NullBooleanField() |
| |
字符 | CharField() |
|
TextField() |
| |
数字 | IntegerField() |
|
PositiveIntegerField() |
| |
SmallIntegerField() |
| |
PositiveSmallIntegerField() |
| |
DecimalField() |
| |
BigIntegerField() |
| |
FloatField() |
| |
日期 | DateField() |
|
TimeField() |
| |
DateTimeField() |
| |
DurationField() |
| |
文件 | FileField() |
|
ImageField() |
| |
FilePathField() |
| |
进制 | BinaryField() |
|
IP | IPAddressField() |
|
GenericIPAddressField() |
| |
其他 | CommaSeparatedIntegerField() |
|
SlugField() |
| |
EmailField() |
| |
URLField() |
| |
UUIDField() |
|
3. ORM字段类与数据库实际的对应关系
分类 | ORM字段类 | mysql数据类型 |
自增 | AutoField() | int |
BigAutoField() | bigint | |
布尔 | BooleanField() | tinyint |
NullBooleanField() | tinyint | |
字符 | CharField() | varchar |
TextField() | logtext | |
数字 | IntegerField() | int |
PositiveIntegerField() | int | |
SmallIntegerField() | smallint | |
PositiveSmallIntegerField() | smallint | |
DecimalField() | decimal | |
BigIntegerField() | bigint | |
FloatField() | double | |
日期 | DateField() | date |
TimeField() | time | |
DateTimeField() | datetime | |
DurationField() | bigint | |
文件 | FileField() | varchar |
ImageField() | varchar | |
FilePathField() | varchar | |
进制 | BinaryField() | longblob |
IP | IPAddressField() | char(15) |
GenericIPAddressField() | char(39) | |
其他 | CommaSeparatedIntegerField() | varchar |
SlugField() | varchar | |
EmailField() | varchar | |
URLField() | varchar | |
UUIDField() | char(32) |
字段参数
1. 常用的字段类参数
字段参数 | 说明 |
null |
|
default |
|
unique |
|
verbose_name |
|
blank |
|
choices |
|
2. null 和 blank 的区别
- blank : 针对于表单
- 如果 blank=True,表示你的表单填写该字段的时候可以不填,比如 admin 界面下增加 model 一条记录的时候。直观的看到就是该字段不是粗体
- 如果 blank=True,那么该字段在数据库上存储的是一个空字符串
- null: 针对于数据库
- 如果 null=True, 那么该字段在数据库上表现为 NULL,而不是一个空字符串
- 注意: 日期型(DateField、TimeField、DateTimeField)和数字型(IntegerField、DecimalField、FloatField)不能接受空字符串,如要想要在填写表单的时候这两种类型的字段为空的话,则需要同时设置 null=True、blank=True;
# models.py
from django.db import models
class BlankNULL(models.Model):
title = models.CharField(max_length=32)
blank_true = models.CharField(max_length=12, blank=True)
null_true = models.CharField(max_length=12, null=True)
null_blank_true = models.CharField(max_length=12, blank=True, null=True)
# views.py
def home(request):
blank_null = BlankNULL.objects.create(title='Kevin')
print(blank_null.__dict__) # {'null_blank_true': None, 'id': 3, 'blank_true': '', 'title': 'Kevin', 'null_true': None}
return render(request, 'home.html')

3. 字段类的参数合集
- 关于数据库的字段参数
字段参数 | 说明 |
null |
|
db_column |
|
default |
|
primary_key |
|
db_index |
|
unique |
|
unique_for_date |
|
unique_for_month |
|
unique_for_year |
|
- 关于Admin的字段参数
字段参数 | 说明 |
verbose_name |
|
blank |
|
editable |
|
help_text |
|
choices |
|
- 关于错误信息和错误验证的字段参数
- error_messages
- 自定义错误信息(字典类型),从而定制想要显示的错误信息
- key值: null, blank, invalid, invalid_choice, unique, unique_for_date
- 如: {'null': "不能为空.", 'invalid': '格式错误'}
- validators
- 自定义错误验证(列表类型),从而定制想要的验证规则
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator, MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
# 如:
test = models.CharField(
max_length=32,
error_messages={
'c1': '优先错信息1',
'c2': '优先错信息2',
'c3': '优先错信息3',
},
validators=[
RegexValidator(regex='root_\d+', message='错误了', code='c1'),
RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
EmailValidator(message='又错误了', code='c3'), ]
)
4. 字段类参数的使用说明
- choices
- choices 只作用于 Admin 和 ModelForm
- 数据库中实际保存的是 choices 参数中 索引为0 的值,而通过Admin或ModelForm所生成的select标签显示的是 choices 参数中 索引为1 的值
- 如果某个字段类配置了该参数,那么在Admin或ModelForm中都会以下拉框的形式显示
- 一般 choices 参数的值都会单独拿出来放到一个变量中
- 在CRM项目中有用到
class ChoicesTable(models.Model):
education_choices = (
(1, '重点大学'),
(2, '普通本科'),
(3, '独立院校'),
(4, '民办本科'),
(5, '大专'),
(6, '民办专科'),
(7, '高中'),
(8, '其他')
)
education = models.IntegerField(verbose_name='学历', choices=education_choices, default=1)
# 等同于
# education = models.IntegerField(verbose_name='学历', choices=((1, '重点大学'), (2, '普通本科'), (3, '独立院校')), default=1)
# ------------------------------------------------
record_choices = (
('checked', "已签到"),
('vacate', "请假"),
('late', "迟到"),
('noshow', "缺勤"),
('leave_early', "早退"),
)
record = models.CharField(verbose_name="上课纪录", choices=record_choices, default="checked", max_length=64)
# 等同于
# record = models.CharField(verbose_name="上课纪录", choices=(('checked', '已签到'), ('vacate', '请假'), ('late', '迟到')), default="checked", max_length=64)
- limit_choices_to
- 语法: limit_choices_to={'所关联表的字段名__条件': 'xxx'}
- 作用: 根据 limit_choices_to 所设置的条件限制 admin 或 ModelForm 所生成的 select 标签中的内容
- 只有一对多和多对多字段类才有该参数
- limit_choices_to 只作用于 admin 或 ModelForm
- 在CRM项目中有用到
# limit_choices_to={'所关联表的字段名__条件': 'xxx'}
# 班级表
class Classes(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=10)
def __str__(self):
return self.name
# 学生表
class Student(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=10)
age = models.IntegerField()
classes = models.ForeignKey(to='Classes', limit_choices_to={'id__in': [1, 2]})
# classes = models.ForeignKey(to='Classes', limit_choices_to={'id': 1})
def __str__(self):
return self.name
5.自定义字段类
- 在Django的ORM中是没有 char 类型的字段类,需要自定义
class FixedCharField(models.Field):
"""
自定义的char类型的字段类
"""
def __init__(self, max_length, *args, **kwargs):
super().__init__(max_length=max_length, *args, **kwargs)
self.length = max_length
def db_type(self, connection):
"""
限定生成数据库表的字段类型为char,长度为length指定的值
"""
return 'char(%s)' % self.length
class Class(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=25)
cname = FixedCharField(max_length=25) # 使用上面自定义的char类型的字段
元信息
ORM对应的类里面包含另一个Meta类,而Meta类封装了一些数据库的信息。主要字段如下:
1.db_table
- 重命名表名,ORM在数据库中的表名默认是 app_类名,可以通过db_table可以重写表名
class Student(models.Model):
username = models.CharField(max_length=10)
age = models.IntegerField()
def __str__(self):
return 'username:{}, age:{}'.format(self.username, self.age)
class Meta:
db_table = 'student'
2.index_together
- 联合索引
class Student(models.Model):
username = models.CharField(max_length=10)
age = models.IntegerField()
def __str__(self):
return 'username:{}, age:{}'.format(self.username, self.age)
class Meta:
index_together = ("username", "age")
3.unique_together
- 联合唯一索引
class Student(models.Model):
username = models.CharField(max_length=10)
age = models.IntegerField()
def __str__(self):
return 'username:{}, age:{}'.format(self.username, self.age)
class Meta:
unique_together = ("username", "age")
4.ordering
- 指定查询出来的数据默认按什么字段排序
- 如果设置了该属性,我们查询到的结果可以直接使用 reverse(),而不需要先排序后再使用 reverse()
- 在日常开发中不建议设置该属性
class Student(models.Model):
username = models.CharField(max_length=10)
age = models.IntegerField()
def __str__(self):
return 'username:{}, age:{}'.format(self.username, self.age)
class Meta:
ordering = ['id'] # 按id升序排列
# ordering = ['-id'] # 按id降序排列,-表示降序
# ordering = ['?id'] # 随机排序,?表示随机
# ordering = ['-age', 'id'] # 以age为降序,如果遇到相同数据再以id升序排列
5.abstract
- 当 django 在进行数据迁移(即: 创建表)的时候,不再对该表进行创建
- 作用: 当该model表设置了 abstract 参数,那么该model表可以当做“父类”,被其他 model 类继承
- 注意: 如果该表类设置了 abstract 参数,那么该表类的外键字段和多对多字段的 to 参数的值必须是“类”,而不是一个字符串,否则就会报错
class User(models.Model):
username = models.CharField(max_length=32, verbose_name='用户名')
password = models.CharField(max_length=32, verbose_name='密码')
roles = models.ManyToManyField(to=Role, verbose_name='角色')
class Meta:
"""
abstract = True 的介绍:
django 在进行数据迁移的时候,不再对该表进行创建
作用: 此类可以当做"父类",被其他Model类继承。
"""
abstract = True
class BackstageUserInfo(User):
phone = models.CharField(max_length=32, null=True, blank=True, verbose_name='电话号码')
age = models.IntegerField(verbose_name='年龄')
gender_choices = (
(1, '男'),
(2, '女')
)
gender = models.IntegerField(choices=gender_choices, default=1, verbose_name='性别')
修改表
- 直接对表的类进行修改就可以了,然后再执行那两条命令
- 注意: 在对创建好的表添加新的字段的时候,如果表中有不能为空的字段或新添加的字段是不能为空的时候,当执行 python manage.py makemigrations 的时候就会报以下的错误 ->(意思就是: 需要你对不能为空的字段添加一个默认值)
- 解决办法: 选择选项1,然后填写默认值,且默认值是必填的,但是有的时候并不需要,可以用单引号代替('')
You are trying to add a non-nullable field 'username' to student without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column) # 选项1:填写该字段的默认值
2) Quit, and let me add a default in models.py # 选项2: 退出,让我在models.py中添加默认值
Select an option: 填写: 选项(1,2)
删除表
- 把需要的删除的表的类注释掉或删除掉,然后执行 makemigrations 和 migrate 命令